home *** CD-ROM | disk | FTP | other *** search
/ Aminet 37 / Aminet 37 (2000)(Schatztruhe)[!][Jun 2000].iso / Aminet / dev / cross / devpic.lha / devpic / source / picasm / picasm.c < prev    next >
C/C++ Source or Header  |  2000-02-27  |  33KB  |  1,538 lines

  1. /*
  2.  * picasm.c
  3.  *
  4.  * Freely distributable for non-commercial use (basically,
  5.  * don't sell this program without my permission. You can
  6.  * use it for developing commercial PIC applications, but
  7.  * of course I am not responsible for any damages caused by
  8.  * this assembler generating bad code or anything like that)
  9.  *
  10.  * Copyright 1995-1998 by Timo Rossi
  11.  * See the file picasm.doc for more information
  12.  * 
  13.  *   email: trossi@iki.fi
  14.  *   www: http://www.iki.fi/trossi/pic/
  15.  *
  16.  */
  17.  
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <stdarg.h>
  22. #include <ctype.h>
  23. #include <time.h>
  24.  
  25. #include "picasm.h"
  26.  
  27. int warnlevel;
  28.  
  29. static int total_line_count;
  30. static int errors, warnings; /* error & warning counts */
  31.  
  32. unsigned short list_flags;
  33.  
  34. /* imported from devices.c */
  35. extern struct pic_type pic_types[];
  36.  
  37. static FILE *list_fp;
  38. static int listing_on;
  39. static int list_loc;
  40. static pic_instr_t *list_ptr;
  41. static long list_val, list_len;
  42.  
  43. int cond_nest_count;
  44. int unique_id_count;
  45.  
  46. /* the current source file/macro */
  47. struct inc_file *current_file;
  48.  
  49. /* Line buffer & pointer to it */
  50. char *line_buf_ptr;
  51. char line_buffer[256];
  52.  
  53. static struct patch *global_patch_list;
  54. struct patch **local_patch_list_ptr;
  55.  
  56. struct pic_type *pic_type;
  57.  
  58. int prog_mem_size;
  59.  
  60. static int reg_file_limit;
  61.  
  62. short code_generated;
  63.  
  64. static pic_instr_t prog_mem[PROGMEM_MAX];
  65. static pic_instr_t data_eeprom[EEPROM_MAX];
  66. static pic_instr_t pic_id[4];
  67. pic_instr_t config_fuses;
  68.  
  69. org_mode_t O_Mode;
  70.  
  71. int prog_location;         /* current address for program code */
  72. int reg_location;   /* current address for register file */
  73. int edata_location; /* current address for data EEPROM */
  74. int org_val;
  75.  
  76. int local_level;
  77.  
  78. /* Error handling */
  79. /*
  80.  * Show line number/line with error message
  81.  */
  82. static void
  83. err_line_ref(void)
  84. {
  85.   struct inc_file *inc;
  86.  
  87.   if(current_file != NULL) {
  88.     inc = current_file;
  89.     if(inc->type != INC_FILE) {
  90.       fprintf(stderr, "(Macro %s line %d) ",
  91.           inc->v.m.sym->name, inc->linenum);
  92.       while(inc != NULL && inc->type != INC_FILE)
  93.     inc = inc->next;
  94.     }
  95.     fprintf(stderr, "File '%s' at line %d:\n",
  96.         inc->v.f.fname, inc->linenum);
  97.     fputs(line_buffer, stderr);
  98.     if(line_buffer[0] != '\0' && line_buffer[strlen(line_buffer)-1] != '\n')
  99.       fputc('\n', stderr);
  100.   }
  101. }
  102.  
  103. /*
  104.  * Warning message
  105.  */
  106. void
  107. warning(char *fmt, ...)
  108. {
  109.   va_list args;
  110.  
  111.   err_line_ref();
  112.   fputs("Warning: ", stderr);
  113.   va_start(args, fmt);
  114.   vfprintf(stderr, fmt, args);
  115.   if(list_fp != NULL) {
  116.     fputs("Warning: ", list_fp);
  117.     vfprintf(list_fp, fmt, args);
  118.     fputc('\n', list_fp);
  119.   }
  120.   fputc('\n', stderr);
  121.   va_end(args);
  122.   warnings++;
  123. }
  124.  
  125. /*
  126.  * skip the end of line, in case of an error
  127.  */
  128. static void
  129. error_lineskip(void)
  130. {
  131.   write_listing_line(0);
  132.   skip_eol();
  133.   get_token();
  134. }
  135.  
  136. /*
  137.  * Error message
  138.  * call error_lineskip() if lskip is non-zero
  139.  *
  140.  */
  141. void
  142. error(int lskip, char *fmt, ...)
  143. {
  144.   va_list args;
  145.  
  146.   err_line_ref();
  147.   fputs("Error: ", stderr);
  148.   va_start(args, fmt);
  149.   vfprintf(stderr, fmt, args);
  150.   if(list_fp != NULL) {
  151.     fputs("Error: ", list_fp);
  152.     vfprintf(list_fp, fmt, args);
  153.     fputc('\n', list_fp);
  154.   }
  155.   fputc('\n', stderr);
  156.   va_end(args);
  157.   if(++errors >= MAX_ERRORS)
  158.     fatal_error("too many errors, aborting");
  159.     
  160.   if(lskip)
  161.     error_lineskip();
  162. }
  163.  
  164. /*
  165.  * Fatal error message
  166.  */
  167. void
  168. fatal_error(char *fmt, ...)
  169. {
  170.   va_list args;
  171.  
  172.   err_line_ref();
  173.   fputs("Fatal error: ", stderr);
  174.   va_start(args, fmt);
  175.   vfprintf(stderr, fmt, args);
  176.   fputc('\n', stderr);
  177.   va_end(args);
  178.   exit(EXIT_FAILURE);
  179. }
  180.  
  181. /* memory allocation */
  182. void *
  183. mem_alloc(int size)
  184. {
  185.   void *p;
  186.  
  187.   if((p = malloc(size)) == NULL)
  188.     fatal_error("Out of memory");
  189.  
  190.   return p;
  191. }
  192.  
  193. /*
  194.  * initialize the assembler
  195.  */
  196. static void
  197. init_assembler(void)
  198. {
  199.   pic_instr_t *cp;
  200.   int n;
  201.  
  202.   init_symtab(); /* initialize symbol table */
  203.  
  204.   /* initialize program memory to invalid values */
  205.   for(n = PROGMEM_MAX, cp = prog_mem; n-- > 0; *cp++ = INVALID_INSTR);
  206.  
  207.   /* initialize data memory to invalid values */
  208.   for(n = EEPROM_MAX, cp = data_eeprom; n-- > 0; *cp++ = INVALID_DATA);
  209.  
  210.   /* initialize jump  patch list */
  211.   global_patch_list = NULL;
  212.  
  213.   prog_location = -1;
  214.   reg_location = -1;
  215.   edata_location = -1;
  216.  
  217.   org_val = -1;
  218.  
  219.   current_file = NULL;
  220.  
  221.   config_fuses = INVALID_CONFIG;
  222.   pic_id[0] = INVALID_ID;
  223.  
  224.   errors = warnings = 0;
  225.  
  226.   list_flags = 0;
  227.   list_len = 0;
  228.   listing_on = 1;
  229.  
  230.   cond_nest_count = 0;
  231.   unique_id_count = 1;
  232.   total_line_count = 0;
  233.   code_generated = 0;
  234.  
  235.   local_level = 0;
  236.  
  237.   ifskip_mode = 0;
  238. }
  239.  
  240. /*
  241.  * generate program code
  242.  */
  243. void gen_code(int val)
  244. {
  245.   if(pic_type == NULL)
  246.     fatal_error("PIC device type not set");
  247.  
  248.   if(O_Mode == O_NONE) {
  249.     O_Mode = O_PROGRAM;
  250.  
  251.     if(org_val < 0) {
  252.       error(0, "ORG value not set");
  253.       prog_location = 0;
  254.       return;
  255.     }
  256.  
  257.     prog_location = org_val;
  258.   } else if(O_Mode != O_PROGRAM) {
  259.     error(0, "ORG mode conflict");
  260.     O_Mode = O_PROGRAM;
  261.     return;
  262.   }
  263.  
  264.   if(prog_location >= prog_mem_size)
  265.     fatal_error("Code address out of range");
  266.  
  267.   if(prog_mem[prog_location] != INVALID_INSTR)
  268.     warning("Overlapping code at 0x%x\n", prog_location);
  269.  
  270.   if((list_flags & LIST_PROG) == 0) {
  271.     list_loc = prog_location;
  272.     list_flags = LIST_LOC | LIST_PROG;
  273.   }
  274.   list_len++;
  275.  
  276.   prog_mem[prog_location++] = val;
  277.  
  278.   code_generated = 1;
  279. }
  280.  
  281. /*
  282.  * Generate data for data EEPROM
  283.  */
  284. void
  285. gen_edata(int val)
  286. {
  287.   if(O_Mode == O_NONE) {
  288.     O_Mode = O_EDATA;
  289.  
  290.     if(org_val < 0) {
  291.       error(0, "ORG value not set");
  292.       edata_location = 0;
  293.       return;
  294.     }
  295.  
  296.     edata_location = org_val;
  297.   } else if(O_Mode != O_EDATA) {
  298.     error(0, "ORG mode conflict");
  299.     O_Mode = O_EDATA;
  300.     return;
  301.   }
  302.  
  303.   if(edata_location >= pic_type->eeprom_size)
  304.     fatal_error("Data EEPROM address out of range");
  305.  
  306.   if(data_eeprom[edata_location] < 0x100)
  307.     warning("Overlapping EEPROM data at 0x%x\n", edata_location);
  308.  
  309.   if((list_flags & LIST_LOC) == 0) {
  310.     list_loc = edata_location;
  311.     list_flags = LIST_LOC | LIST_EDATA;
  312.   }
  313.   list_len++;
  314.  
  315.   data_eeprom[edata_location++] = val;
  316.  
  317.   code_generated = 1;
  318. }
  319.  
  320. /*
  321.  * Write one line of Intel-hex file
  322.  */
  323. static void
  324. write_hex_record(FILE *fp,
  325.                int reclen, /* length (in words) */
  326.                int loc, /* address */
  327.                pic_instr_t *data, /* pointer to word data */
  328.                int format) /* IHX8M or IHX16 */
  329. {
  330.   int check = 0;
  331.  
  332.   switch(format) {
  333.     case IHX8M:
  334.       fprintf(fp, ":%02X%04X00", 2*reclen, 2*loc);
  335.       check += ((2*loc) & 0xff) + (((2*loc) >> 8) & 0xff) + 2*reclen;
  336.       break;
  337.  
  338.     case IHX16:
  339.       fprintf(fp, ":%02X%04X00", reclen, loc);
  340.       check += (loc & 0xff) + ((loc >> 8) & 0xff) + reclen;
  341.       break;
  342.   }
  343.  
  344.   while(reclen--) {
  345.     switch(format) {
  346.       case IHX8M:
  347.         fprintf(fp, "%02X%02X",
  348.         (int)(*data & 0xff), (int)((*data >> 8) & 0xff));
  349.     break;
  350.  
  351.       case IHX16:
  352.     fprintf(fp, "%02X%02X",
  353.         (int)((*data >> 8) & 0xff), (int)(*data & 0xff));
  354.     break;
  355.     }
  356.     check += (*data & 0xff) + ((*data >> 8) & 0xff);
  357.     data++;
  358.   }
  359.  
  360.   /* write checksum, assumes 2-complement */
  361.   fprintf(fp, "%02X" HEX_EOL, (-check) & 0xff);
  362. }
  363.  
  364. /*
  365.  * Write output file in ihx8m or ihx16-format
  366.  *
  367.  */
  368. static void
  369. write_output(char *fname, int format)
  370. {
  371.   int loc, reclen;
  372.   FILE *fp;
  373.  
  374.   if((fp = fopen(fname, "w")) == NULL)
  375.     fatal_error("Can't create file '%s'", fname);
  376.  
  377.   /* program */
  378.   for(loc = 0;;) {
  379.     while(loc < prog_mem_size && prog_mem[loc] == INVALID_INSTR)
  380.       loc++;
  381.  
  382.     if(loc >= prog_mem_size)
  383.       break;
  384.       
  385.     reclen = 0;
  386.     while(reclen < 8 && loc < prog_mem_size
  387.       && prog_mem[loc] != INVALID_INSTR) {
  388.       loc++;
  389.       reclen++;
  390.     }
  391.     write_hex_record(fp, reclen, loc-reclen, &prog_mem[loc-reclen], format);
  392.   }
  393.  
  394.   /* PIC ID */
  395.   if(pic_id[0] != INVALID_ID) {
  396.     switch(pic_type->instr_set) {
  397.       case PIC12BIT:
  398.         write_hex_record(fp, 4, prog_mem_size, pic_id, format);
  399.     break;
  400.  
  401.       case PIC14BIT:
  402.     write_hex_record(fp, 4, 0x2000, pic_id, format);
  403.     break;
  404.     }
  405.   }
  406.  
  407.   /* config fuses */
  408.   if(config_fuses != INVALID_CONFIG) {
  409.     write_hex_record(fp, 1, pic_type->fuse_addr, &config_fuses, format);
  410.   }
  411.  
  412.   if(pic_type->eeprom_size > 0) { /* data EEPROM */
  413.     for(loc = 0;;) {
  414.       while(loc < pic_type->eeprom_size && data_eeprom[loc] >= 0x100)
  415.     loc++;
  416.         
  417.       if(loc >= pic_type->eeprom_size)
  418.     break;
  419.         
  420.       reclen = 0;
  421.       while(reclen < 8 && loc < pic_type->eeprom_size
  422.         && data_eeprom[loc] < 0x100) {
  423.     loc++;
  424.     reclen++;
  425.       }
  426.       write_hex_record(fp, reclen, 0x2100+loc-reclen,
  427.                &data_eeprom[loc-reclen], format);
  428.     }
  429.   }
  430.  
  431.   fputs(":00000001FF" HEX_EOL , fp); /* end record */
  432.   fclose(fp);
  433. }
  434.  
  435. /*
  436.  * Write one line to listing file (if listing is enabled)
  437.  */
  438. void
  439. write_listing_line(int cond_flag)
  440. {
  441.   int i;
  442.  
  443.   if(list_fp != NULL && listing_on) {
  444.     fprintf(list_fp, "%04d%c%c",
  445.         ++total_line_count,
  446.         (current_file != NULL && current_file->type == INC_MACRO ?
  447.          '+' : ' '),
  448.         (cond_flag ? '!' : ' '));
  449.  
  450.     if(line_buffer[0] != '\0') {
  451.       if(list_flags & LIST_VAL)    {
  452.     fprintf(list_fp, "%08lX  ", list_val);
  453.       } else {
  454.     if(list_flags & LIST_LOC)
  455.       fprintf(list_fp, "%04X", list_loc);
  456.     else
  457.       fputs("    ", list_fp);
  458.  
  459.     if((list_flags & (LIST_PROG|LIST_EDATA|LIST_PTR)) != 0) {
  460.       fputc(((list_flags & LIST_FORWARD) ? '?' : ' '), list_fp);
  461.       if(list_flags & LIST_PROG) {
  462.         fprintf(list_fp, "%04X ", prog_mem[list_loc]);
  463.       } else if(list_flags & LIST_EDATA) {
  464.         fprintf(list_fp, "%04X ", data_eeprom[list_loc]);
  465.       } else if(list_flags & LIST_PTR) {
  466.         fprintf(list_fp, "%04X ", *list_ptr++);
  467.       }
  468.     } else {
  469.       fputs("      ", list_fp);
  470.     }
  471.       }
  472.  
  473.       fputs(line_buffer, list_fp);
  474.       if(line_buffer[0] != '\0'
  475.      && line_buffer[strlen(line_buffer)-1] != '\n')
  476.     fputc('\n', list_fp);
  477.  
  478.       list_len--;
  479.       for(i = 0; i < list_len; i++) {
  480.     list_loc++;
  481.     fprintf(list_fp, "%04d%c ",
  482.         total_line_count,
  483.         (current_file != NULL
  484.          && current_file->type == INC_MACRO ?
  485.          '+' : ' '));
  486.  
  487.     if(list_flags & LIST_LOC)
  488.       fprintf(list_fp, "%04X", list_loc);
  489.     else
  490.       fputs("    ", list_fp);
  491.  
  492.     if(list_flags & LIST_PROG) {
  493.       fprintf(list_fp, " %04X\n", prog_mem[list_loc]);
  494.     } else if(list_flags & LIST_EDATA) {
  495.       fprintf(list_fp, " %04X\n", data_eeprom[list_loc]);
  496.     } else if(list_flags & LIST_PTR) {
  497.       fprintf(list_fp, " %04X\n", *list_ptr++);
  498.     }
  499.       }
  500.     }
  501.  
  502.     if(listing_on < 0)
  503.       listing_on = 0;
  504.   }
  505.   list_flags = 0;
  506.   list_len = 0;
  507. }
  508.  
  509. /*
  510.  * parse and handle OPT-directive
  511.  * (this is special as it must be done as macro definition time
  512.  *  if inside a macro)
  513.  */
  514. static int
  515. handle_opt(void)
  516. {
  517.   if(token_type != TOK_IDENTIFIER) {
  518.     error(1, "OPT syntax error");
  519.     return FAIL;
  520.   }
  521.   /*
  522.    * Note: when listing is turned off, 'listing_on' is set to -1
  523.    * here and the listing routine sets it to zero after listing
  524.    * the line containing the 'opt nol'.
  525.    */
  526.   if(strcasecmp(token_string, "nol") == 0
  527.      || strcasecmp(token_string, "nolist") == 0) {
  528.     listing_on = -1;
  529.   } else if(strcasecmp(token_string, "l") == 0
  530.       || strcasecmp(token_string, "list") == 0) {
  531.     listing_on = 1;
  532.   } else {
  533.     error(1, "OPT syntax error");
  534.     return FAIL;
  535.   }
  536.  
  537.   get_token();
  538.   return OK;
  539. }
  540.  
  541. /*
  542.  * Define a macro
  543.  */
  544. static void
  545. define_macro(char *name)
  546. {
  547.   struct symbol *sym;
  548.   struct macro_line *ml;
  549.   int t;
  550.  
  551.   if(token_type != TOK_NEWLINE && token_type != TOK_EOF)
  552.     error(0, "Extraneous characters after a valid source line");
  553.   skip_eol();
  554.  
  555.   write_listing_line(0);
  556.  
  557.   sym = add_symbol(name, SYMTAB_GLOBAL);
  558.   sym->type = SYM_MACRO;
  559.   sym->v.text = NULL;
  560.   ml = NULL;
  561.  
  562.   for(;;) {
  563.     get_token(); /* read first token on next line */
  564.     t = 0;
  565.     if(token_type == TOK_IDENTIFIER) {
  566.       t = 1;
  567.       get_token();
  568.       if(token_type == TOK_COLON)
  569.     get_token();
  570.     }
  571.     if(token_type == TOK_EOF || token_type == KW_END)
  572.       fatal_error("Macro definition not terminated");
  573.  
  574.     if(token_type == KW_MACRO)
  575.       fatal_error("Nested macro definitions not allowed");
  576.  
  577.     if(token_type == KW_ENDM) /* end macro definition */
  578.       break;
  579.  
  580. /* OPT must be handled inside macros at definition time */
  581.     if(token_type == KW_OPT) {
  582.       get_token();
  583.       handle_opt();
  584.     } else {
  585.       if(ml == NULL) {
  586.     ml = mem_alloc(sizeof(struct macro_line)
  587.                +strlen(line_buffer));
  588.     sym->v.text = ml;
  589.       } else {
  590.     ml->next = mem_alloc(sizeof(struct macro_line)
  591.                  +strlen(line_buffer));
  592.     ml = ml->next;
  593.       }
  594.       strcpy(ml->text, line_buffer);
  595.       ml->next = NULL;
  596.     }
  597.  
  598.     write_listing_line(0);
  599.  
  600.     line_buf_ptr = NULL;
  601.     tok_char = ' ';
  602.   }
  603.   if(t)
  604.     error(0, "Label not allowed with ENDM");
  605.   get_token();
  606. }
  607.  
  608. /*
  609.  * Skip subroutine used by the conditional assembly directives
  610.  * return: -1=premature EOF, 0=ok, 1=label (not allowed)
  611.  */
  612. static int
  613. if_else_skip(void)
  614. {
  615.   int t, ccount;
  616.  
  617.   ccount = 0;
  618.   ifskip_mode++;
  619.   do {
  620.     skip_eol();
  621.     get_token();
  622.     write_listing_line(1);
  623.  
  624.     t = 0;
  625.     if(token_type == TOK_IDENTIFIER) {
  626.       t = 1;
  627.       get_token();
  628.       if(token_type == TOK_COLON)
  629.     get_token();
  630.     }
  631.     if(token_type == KW_IF) {
  632.       ccount++;
  633.     } else if(token_type == KW_ENDIF) {
  634.       if(ccount <= 0)
  635.     break;
  636.       ccount--;
  637.     } else if(token_type == KW_ELSE && ccount <= 0) {
  638.       break;
  639.     }
  640.   } while(token_type != TOK_EOF && token_type != KW_END);
  641.  
  642.   ifskip_mode--;
  643.   return (token_type == TOK_EOF || token_type == KW_END) ? -1 : t;
  644. }
  645.  
  646. /*
  647.  * Add a patch pointing to the current location
  648.  */
  649. void
  650. add_patch(int tab, struct symbol *sym, patchtype_t type)
  651. {
  652.   struct patch **patch_list_ptr, *ptch;
  653.  
  654.   patch_list_ptr =
  655.     (tab == SYMTAB_GLOBAL ? &global_patch_list : local_patch_list_ptr);
  656.  
  657.   if(O_Mode == O_NONE) {
  658.     O_Mode = O_PROGRAM;
  659.     if(org_val < 0) {
  660.       error(0, "ORG value not set");
  661.       prog_location = 0;
  662.       return;
  663.     }
  664.     prog_location = org_val;
  665.   }
  666.  
  667.   ptch = mem_alloc(sizeof(struct patch));
  668.   ptch->label = sym;
  669.   ptch->type = type;
  670.   ptch->location = prog_location;
  671.  
  672.   /* add a new patch to patch_list */
  673.   ptch->next = *patch_list_ptr;
  674.   *patch_list_ptr = ptch;
  675. }  
  676.  
  677. /*
  678.  * Apply the store patches and also free the patch list
  679.  */
  680. static void
  681. apply_patches(struct patch *patch_list)
  682. {
  683.   struct patch *ptch, *p2;
  684.  
  685.   /*
  686.    * fix forward jumps/calls
  687.    */
  688.   for(ptch = patch_list; ptch != NULL; ptch = p2) {
  689.     p2 = ptch->next;
  690.  
  691.     if(ptch->label->type == SYM_FORWARD)
  692.       error(0, "Undefined label '%s%s'",
  693.         (patch_list == global_patch_list ? "" : "="),
  694.         ptch->label->name);
  695.     else
  696.       switch(ptch->type) {
  697.         case PATCH8:
  698.       if(pic_type->instr_set == PIC12BIT && (ptch->label->v.value & 0x100) != 0
  699.          && (prog_mem[ptch->location] & 0xff00) == 0x900)
  700.         error(0, "CALL address in upper half of a page (label '%s%s')",
  701.           (patch_list == global_patch_list ? "" : "="),
  702.           ptch->label->name);
  703.  
  704.       prog_mem[ptch->location] =
  705.         (prog_mem[ptch->location] & 0xff00)
  706.           | (ptch->label->v.value & 0xff);
  707.       break;
  708.  
  709.     case PATCH9:
  710.       prog_mem[ptch->location] =
  711.         (prog_mem[ptch->location] & 0xfe00)
  712.           | (ptch->label->v.value & 0x1ff);
  713.       break;
  714.  
  715.     case PATCH11:
  716.       prog_mem[ptch->location] =
  717.         (prog_mem[ptch->location] & 0xf800)
  718.           | (ptch->label->v.value & 0x7ff);
  719.       break;
  720.       }
  721.     mem_free(ptch);
  722.   }
  723. }
  724.  
  725. /*
  726.  * Generate code for an instruction with 8-bit literal data
  727.  * allows forward references
  728.  */
  729. int
  730. gen_byte_c(int instr_code)
  731. {
  732.   int t, symtype;
  733.   long val;
  734.   struct symbol *sym;
  735.  
  736.   t = 0;
  737.   if(token_type == TOK_IDENTIFIER || token_type == TOK_LOCAL_ID) {
  738.     symtype =
  739.       (token_type == TOK_IDENTIFIER ? SYMTAB_GLOBAL : SYMTAB_LOCAL);
  740.  
  741.     if(symtype == SYMTAB_LOCAL && local_level == 0) {
  742.       error(1, "Local symbol outside a LOCAL block");
  743.       return FAIL;
  744.     }
  745.  
  746.     sym = lookup_symbol(token_string, symtype);
  747.     if(sym == NULL || sym->type == SYM_FORWARD)    {
  748.       if(sym == NULL) {
  749.     sym = add_symbol(token_string, symtype);
  750.     sym->type = SYM_FORWARD;
  751.       }
  752.  
  753.       add_patch(symtype, sym, PATCH8);
  754.       get_token();
  755.       gen_code(instr_code);
  756.       list_flags |= LIST_FORWARD;
  757.       return OK;
  758.     }
  759.   }
  760.  
  761.   val = get_expression();
  762.   if(expr_error)
  763.     return FAIL;
  764.  
  765.   if(val < -0x80 || val > 0xff) {
  766.     error(0, "8-bit literal out of range");
  767.     return FAIL;
  768.   }
  769.  
  770.   gen_code(instr_code | (val & 0xff));
  771.   return OK;
  772. }
  773.  
  774. /*
  775.  * check if the current token is a valid ORG mode specifier
  776.  * and return the mode (or O_NONE if not valid mode specifier)
  777.  */
  778. static int
  779. org_mode(void)
  780. {
  781.   if(token_type == KW_EDATA)
  782.     return O_EDATA;
  783.  
  784.   if(token_type == TOK_IDENTIFIER) {
  785.     if(strcasecmp(token_string, "code") == 0)
  786.       return O_PROGRAM;
  787.  
  788.     if(strcasecmp(token_string, "reg") == 0)
  789.       return O_REGFILE;
  790.   }
  791.  
  792.   return O_NONE;
  793. }
  794.  
  795. /*
  796.  * The assembler itself
  797.  */
  798. static void
  799. assembler(char *fname)
  800. {
  801.   static char symname[256];
  802.   struct symbol *sym;
  803.   int op, t, symtype;
  804.   long val;
  805.   char *cp;
  806.   struct pic_type *pic;
  807.  
  808.   if(pic_type != NULL) {
  809.     sprintf(symname, "__%s", pic_type->name);
  810.     sym = add_symbol(symname, SYMTAB_GLOBAL);
  811.     sym->type = SYM_DEFINED;
  812.     sym->v.value = 1;
  813.   }
  814.  
  815.   begin_include(fname);
  816.   get_token();
  817.  
  818.   while(token_type != TOK_EOF) {
  819.     sym = NULL;
  820.     if(token_type == TOK_IDENTIFIER || token_type == TOK_LOCAL_ID) {
  821.       symtype =
  822.     (token_type == TOK_IDENTIFIER ? SYMTAB_GLOBAL : SYMTAB_LOCAL);
  823.  
  824.       if(symtype == SYMTAB_LOCAL && local_level == 0) {
  825.     error(1, "Local symbol outside a LOCAL block");
  826.     continue;
  827.       }
  828.  
  829.       t = (line_buf_off == 0);
  830.  
  831.       strcpy(symname, token_string);
  832.       sym = lookup_symbol(symname, symtype);
  833.       if(sym != NULL && sym->type == SYM_MACRO) {
  834.     /* skip whitespace */
  835.     while(tok_char != '\n' && isspace(tok_char))
  836.       read_src_char();
  837.  
  838.     if(line_buf_ptr != NULL &&
  839.        strncasecmp(line_buf_ptr-1, "macro", 5) == 0 &&
  840.        line_buf_ptr[4] != '.' && line_buf_ptr[4] != '_' &&
  841.        !isalnum((unsigned char)line_buf_ptr[4])) {
  842.       error(1, "Multiple definition of macro '%s'", symname);
  843.       continue;
  844.     }
  845.  
  846.     expand_macro(sym);
  847.     continue;
  848.       }
  849.  
  850.       get_token();
  851.       switch(token_type) {
  852.         case KW_MACRO:
  853.       get_token();
  854.       if(sym != NULL) {
  855.         error(1, "Multiply defined symbol '%s%s'",
  856.           (symtype == SYMTAB_LOCAL ? "=" : ""),
  857.           sym->name);
  858.         continue;
  859.       }
  860.       define_macro(symname);
  861.       goto line_end;
  862.  
  863.     case KW_EQU:
  864.       if(sym != NULL) {
  865.         if(sym->type != SYM_FORWARD)
  866.           error(0, "Multiply defined symbol '%s%s'",
  867.             (symtype == SYMTAB_LOCAL ? "=" : ""),
  868.             sym->name);
  869.       } else
  870.         sym = add_symbol(symname, symtype);
  871.       get_token();
  872.       sym->type = SYM_DEFINED;
  873.       sym->v.value = get_expression();
  874.       if(expr_error)
  875.         continue; /* error_lineskip() done in expr.c */
  876.  
  877.       list_val = sym->v.value;
  878.       list_flags = LIST_VAL;
  879.       goto line_end;
  880.  
  881.     case KW_SET:
  882.       if(sym != NULL && sym->type != SYM_SET)
  883.         error(0, "Multiply defined symbol '%s%s'",
  884.           (symtype == SYMTAB_LOCAL ? "=" : ""),
  885.           sym->name);
  886.       else if(sym == NULL)
  887.         sym = add_symbol(symname, symtype);
  888.       get_token();
  889.       sym->type = SYM_SET;
  890.       sym->v.value = get_expression();
  891.       if(expr_error)
  892.         continue;
  893.  
  894.       list_val = sym->v.value;
  895.       list_flags = LIST_VAL;
  896.       goto line_end;
  897.  
  898.     case TOK_COLON:
  899.       get_token();
  900.       goto do_label;
  901.  
  902.     default:
  903.       if(t == 0)
  904.         warning("Label not in the beginning of a line");
  905.  
  906. do_label:
  907.       switch(O_Mode) {
  908.         case O_PROGRAM:
  909.           t = prog_location;
  910.           break;
  911.  
  912.         case O_REGFILE:
  913.           t = reg_location;
  914.           break;
  915.  
  916.         case O_EDATA:
  917.           t = edata_location;
  918.           break;
  919.  
  920.         case O_NONE:
  921.           t = org_val;
  922.           break;
  923.       }
  924.  
  925.       if(t < 0) {
  926.         error(0, "ORG value not set");
  927.       } else {
  928.         if(sym != NULL && sym->type != SYM_FORWARD)
  929.           error(0, "Multiply defined symbol '%s%s'",
  930.             (symtype == SYMTAB_LOCAL ? "=" : ""),
  931.             sym->name);
  932.         if(sym == NULL)
  933.           sym = add_symbol(symname, symtype);
  934.         sym->type = SYM_DEFINED;
  935.         sym->v.value = t;
  936.         list_loc = t;
  937.         list_flags = LIST_LOC;
  938.       }
  939.       break;
  940.       }
  941.     }
  942.  
  943.     /* if this line has a label, 'sym' points to it */
  944.  
  945.     if(token_type == TOK_NEWLINE) {
  946.       write_listing_line(0);
  947.       get_token();
  948.       continue;
  949.     }
  950.  
  951.     if(token_type == TOK_IDENTIFIER &&
  952.        (sym = lookup_symbol(token_string, SYMTAB_GLOBAL))
  953.        != NULL && sym->type == SYM_MACRO) {
  954.       expand_macro(sym);
  955.       continue;
  956.     }
  957.  
  958.     if(token_type == KW_END)
  959.       break;
  960.  
  961.     if(token_type == KW_ERROR) {
  962.       while(isspace((unsigned char)(*line_buf_ptr)))
  963.      line_buf_ptr++;
  964.       error(1, "%s", line_buf_ptr);
  965.       continue;
  966.     }
  967.       
  968.     op = token_type;
  969.     get_token();
  970.  
  971.     switch(op) {
  972.       case KW_INCLUDE:
  973.       if(token_type != TOK_STRCONST) {
  974.     error(1, "Missing file name after INCLUDE");
  975.     continue;
  976.       }
  977.  
  978.       strcpy(symname, token_string);
  979.       get_token();
  980.       if(token_type != TOK_NEWLINE && token_type != TOK_EOF)
  981.     error(0, "Extraneous characters after a valid source line");
  982.  
  983.       begin_include(symname);
  984.  
  985.       write_listing_line(0);
  986.       get_token();
  987.       continue;
  988.  
  989.     case KW_SET:
  990.     case KW_EQU:
  991.       if(sym == NULL)
  992.     error(1, "SET/EQU without a label");
  993.       else
  994.     error(1, "SET/EQU syntax error");
  995.       continue;
  996.  
  997.     case KW_MACRO:
  998.       error(1, "MACRO without a macro name");
  999.       continue;
  1000.  
  1001.     case KW_ENDM:
  1002.       error(1, "ENDM not allowed outside a macro");
  1003.       continue;
  1004.  
  1005.     case KW_EXITM:
  1006.       /*
  1007.        * EXITM works now (version 0.97). Strange that
  1008.        * nobody noticed that it wasn't implemented
  1009.        * at all in previous versions.
  1010.        */
  1011.       if(current_file == NULL || current_file->type != INC_MACRO) {
  1012.     error(1, "EXITM not allowed outside a macro");
  1013.     continue;
  1014.       }
  1015.       cond_nest_count = current_file->cond_nest_count;
  1016.       end_include();
  1017.       break;
  1018.  
  1019.     case KW_OPT:
  1020.       if(handle_opt() != OK) {
  1021.     error_lineskip();
  1022.     continue;
  1023.       }
  1024.       break;
  1025.  
  1026.     case KW_LOCAL:
  1027.       add_local_symtab();
  1028.       break;
  1029.  
  1030.     case KW_ENDLOCAL:
  1031.       if(local_level == 0) {
  1032.     error(1, "ENDLOCAL without LOCAL");
  1033.     continue;
  1034.       }
  1035.  
  1036.       apply_patches(*local_patch_list_ptr);
  1037.       remove_local_symtab();
  1038.       break;
  1039.         
  1040.     case KW_IF:
  1041.       if(sym != NULL)
  1042.     error(0, "Label not allowed with IF");
  1043.  
  1044.       val = get_expression();
  1045.  
  1046.       if(token_type != TOK_NEWLINE && token_type != TOK_EOF)
  1047.     error(0, "Extraneous characters after a valid source line");
  1048.  
  1049.       if(val == 0) {
  1050.     write_listing_line(0);
  1051.     t=if_else_skip();
  1052.     if(t == -1)
  1053.       fatal_error("Conditional not terminated");
  1054.     else if(t == 1)
  1055.       error(0, "Label not allowed with %s",
  1056.         (token_type == KW_ELSE ? "ELSE" : "ENDIF"));
  1057.  
  1058.     if(token_type == KW_ELSE)
  1059.       cond_nest_count++;
  1060.     get_token();
  1061.     goto line_end2;
  1062.       } else
  1063.     cond_nest_count++;
  1064.       break;
  1065.  
  1066.     case KW_ELSE:
  1067.       if(sym != NULL)
  1068.     error(0, "Label not allowed with %s", "ELSE");
  1069.  
  1070.       if(current_file == NULL
  1071.      || cond_nest_count <= current_file->cond_nest_count)
  1072.     error(0, "ELSE without IF");
  1073.  
  1074.       write_listing_line(0);
  1075.       t = if_else_skip();
  1076.       if(t == -1)
  1077.     fatal_error("Conditional not terminated");
  1078.       else if(t == 1)
  1079.     error(0, "Label not allowed with %s",
  1080.           (token_type == KW_ELSE ? "ELSE" : "ENDIF"));
  1081.  
  1082.       if(token_type == KW_ELSE)
  1083.     error(0, "Multiple ELSE statements with one IF");
  1084.  
  1085.       cond_nest_count--;
  1086.  
  1087.       get_token();
  1088.       goto line_end2;
  1089.  
  1090.     case KW_ENDIF:
  1091.       if(sym != NULL)
  1092.     error(0, "Label not allowed with %s", "ENDIF");
  1093.  
  1094.       if(current_file == NULL
  1095.      || cond_nest_count <= current_file->cond_nest_count)
  1096.     error(0, "ENDIF without IF");
  1097.  
  1098.       cond_nest_count--;
  1099.       break;
  1100.  
  1101.     case KW_ORG:
  1102.       if(pic_type == NULL)
  1103.     fatal_error("PIC device type not set");
  1104.  
  1105.       org_val = -1;
  1106.       if((t = org_mode()) != O_NONE) {
  1107.     get_token();
  1108.     O_Mode = (org_mode_t)t;
  1109.     switch(O_Mode) {
  1110.       case O_PROGRAM:
  1111.       case O_NONE: /* shut up GCC warning, cannot really happen here */
  1112.         org_val = prog_location;
  1113.         break;
  1114.  
  1115.       case O_REGFILE:
  1116.         org_val = reg_location;
  1117.         break;
  1118.  
  1119.       case O_EDATA:
  1120.         org_val = edata_location;
  1121.         break;
  1122.     }
  1123.     if(org_val < 0) {
  1124.       error(0, "ORG value not set");
  1125.       O_Mode = O_NONE;
  1126.     }
  1127.     break;
  1128.       }
  1129.  
  1130.       val = get_expression();
  1131.       if(expr_error)
  1132.     continue;
  1133.  
  1134.       if(val < 0 || val >= prog_mem_size) {
  1135.     error(1, "ORG value out of range");
  1136.     continue;
  1137.       }
  1138.  
  1139.       org_val = val;
  1140.       O_Mode = O_NONE;
  1141.  
  1142.       if(token_type == TOK_COMMA) {
  1143.     get_token();
  1144.     if((t = org_mode()) == O_NONE) {
  1145.       error(0, "Invalid ORG mode");
  1146.     } else {
  1147.       O_Mode = (org_mode_t)t;
  1148.       switch(O_Mode)
  1149.       {
  1150.         case O_PROGRAM:
  1151.         case O_NONE: /* shut up GCC warning, cannot really happen here */
  1152.           prog_location = org_val;
  1153.           break;
  1154.           
  1155.         case O_REGFILE:
  1156.           reg_location = org_val;
  1157.           break;
  1158.           
  1159.         case O_EDATA:
  1160.           edata_location = org_val;
  1161.           break;
  1162.       }
  1163.     }
  1164.           
  1165.     get_token();
  1166.       }
  1167.         
  1168.       list_loc = org_val;
  1169.       list_flags = LIST_LOC;
  1170.       break;
  1171.  
  1172.     case KW_DS:
  1173.       val = get_expression();
  1174.       if(expr_error)
  1175.     continue;
  1176.  
  1177.       if(O_Mode == O_NONE) {
  1178.     O_Mode = O_REGFILE;
  1179.     if(org_val < 0) {
  1180.       error(0, "ORG value not set");
  1181.       reg_location = 0;
  1182.     } else
  1183.       reg_location = org_val;
  1184.       }
  1185.  
  1186.       if(O_Mode != O_REGFILE)
  1187.     error(0, "ORG mode conflict");
  1188.       else {
  1189.     if(reg_location >= reg_file_limit)
  1190.       fatal_error("Register file address out of range");
  1191.     list_loc = reg_location;
  1192.     list_flags = LIST_LOC;
  1193.     reg_location += val;
  1194.       }
  1195.       break;
  1196.  
  1197.     case KW_EDATA:
  1198.       if(pic_type == NULL)
  1199.     fatal_error("PIC device type not set");
  1200.  
  1201.       if(pic_type->eeprom_size == 0) {
  1202.     error(1, "PIC%s does not have data EEPROM", pic_type->name);
  1203.     continue;
  1204.       }
  1205.  
  1206.       for(;;) {
  1207.     if(token_type == TOK_STRCONST) {
  1208.       for(cp = token_string; *cp != '\0'; cp++)
  1209.         gen_edata((int)((unsigned char)(*cp)));
  1210.       get_token();
  1211.     } else {
  1212.       val = get_expression();
  1213.       if(expr_error)
  1214.         break;
  1215.  
  1216.       if(val < 0 || val > 0xff) {
  1217.         error(0, "Data EEPROM byte out of range");
  1218.       } else
  1219.         gen_edata(val);
  1220.     }
  1221.     if(token_type != TOK_COMMA)
  1222.       break;
  1223.  
  1224.     get_token();
  1225.       }
  1226.       break;
  1227.  
  1228.     case KW_CONFIG:
  1229.       if(pic_type == NULL)
  1230.     fatal_error("PIC device type not set");
  1231.  
  1232.       if(config_fuses != INVALID_CONFIG) {
  1233.     error(1, "Multiple CONFIG definitions");
  1234.     continue;
  1235.       }
  1236.  
  1237.       parse_config();
  1238.  
  1239.       list_flags = LIST_PTR;
  1240.       list_ptr = &config_fuses;
  1241.       list_len = 1;
  1242.       break;
  1243.  
  1244.       /* Device type */
  1245.     case KW_DEVICE:
  1246.       if(token_type != TOK_IDENTIFIER && token_type != TOK_STRCONST) {
  1247.     error(1, "DEVICE requires a device type");
  1248.     continue;
  1249.       }
  1250.  
  1251.       cp = token_string;
  1252.       if(strncasecmp(token_string, "PIC", 3) == 0)
  1253.     cp += 3;
  1254.  
  1255.       for(pic = pic_types; pic->name != NULL; pic++) {
  1256.     if(strcasecmp(pic->name, cp) == 0)
  1257.       break;
  1258.       }
  1259.       if(pic->name == NULL)
  1260.     fatal_error("Invalid PIC device type");
  1261.  
  1262.       get_token();
  1263.       if(pic_type == pic)
  1264.     break;
  1265.  
  1266.       if(pic_type != NULL) {
  1267.     error(1, "Duplicate DEVICE setting");
  1268.     continue;
  1269.       }
  1270.       pic_type = pic;
  1271.       prog_mem_size = pic_type->progmem_size;
  1272.       reg_file_limit = pic_type->regfile_limit;
  1273.  
  1274.       sprintf(symname, "__%s", pic_type->name);
  1275.       sym = add_symbol(symname, SYMTAB_GLOBAL);
  1276.       sym->type = SYM_DEFINED;
  1277.       sym->v.value = 1;
  1278.       break;
  1279.  
  1280.       /* PIC ID */
  1281.     case KW_PICID:
  1282.       if(pic_type == NULL)
  1283.     fatal_error("PIC device type not set");
  1284.  
  1285.       if(pic_id[0] != INVALID_ID) {
  1286.     error(1, "Multiple ID definitions");
  1287.     continue;
  1288.       }
  1289.  
  1290.       /*
  1291.        * should check if ID is really allowed for all PIC types.
  1292.        * Microchip 1994 databook specfically says that ID is not
  1293.        * implemented on PIC16C6x/74... but 1995/96 databook
  1294.        * has different information about that...
  1295.        */
  1296.  
  1297.       for(t = 0;;) {
  1298.     val = get_expression();
  1299.     if(expr_error)
  1300.       continue;
  1301.  
  1302.     if(val < 0 || val > 0x3fff)
  1303.       error(0, "PIC ID value out of range");
  1304.     else {
  1305.       if(t >= 4) {
  1306.         error(1, "PIC ID too long (max 4 bytes)");
  1307.         continue;
  1308.       }
  1309.       pic_id[t] = (pic_instr_t)val;
  1310.     }
  1311.  
  1312.     t++;
  1313.  
  1314.     if(token_type != TOK_COMMA)
  1315.       break;
  1316.  
  1317.     get_token();
  1318.       }
  1319.  
  1320.       if(t > 0) {
  1321.     list_flags = LIST_PTR;
  1322.     list_len = t;
  1323.     list_ptr = pic_id;
  1324.  
  1325.     while(t < 4)
  1326.       pic_id[t++] = 0x3fff;
  1327.       }
  1328.       break;
  1329.  
  1330.       /* mnemonics */
  1331.  
  1332.     default:
  1333.       switch(pic_type->instr_set) {
  1334.         case PIC12BIT:
  1335.       t = assemble_12bit_mnemonic(op);
  1336.       break;
  1337.  
  1338.     case PIC14BIT:
  1339.     default:
  1340.       t = assemble_14bit_mnemonic(op);
  1341.       break;
  1342.     }
  1343.       if(t != OK)
  1344.     continue;
  1345.       break;
  1346.     }
  1347.  
  1348. line_end:
  1349.     write_listing_line(0);
  1350.  
  1351. line_end2:
  1352.     if(token_type == TOK_EOF)
  1353.       continue;
  1354.  
  1355.     if(token_type != TOK_NEWLINE) {
  1356.       error(0, "Extraneous characters after a valid source line");
  1357.       skip_eol();
  1358.     }
  1359.     get_token();
  1360.   } /* while(token_type != TOK_EOF) */
  1361.  
  1362.   /*
  1363.    * Close all open source files
  1364.    * (only really necessary if END has been used)
  1365.    */
  1366.   while(current_file != NULL)
  1367.     end_include();
  1368.  
  1369.   if(local_level > 0)
  1370.     error(0, "LOCAL not terminated with ENDLOCAL");
  1371.  
  1372.   apply_patches(global_patch_list);
  1373. }
  1374.  
  1375. /*
  1376.  * main program
  1377.  */
  1378. int
  1379. main(int argc, char *argv[])
  1380. {
  1381.   static char in_filename[256], out_filename[256], list_filename[256];
  1382.   static int out_format = IHX8M;
  1383.   static int listing = 0, symdump = 0;
  1384.   char *p;
  1385.   time_t ti;
  1386.   struct tm *tm;
  1387.  
  1388.   pic_type = NULL;
  1389.   out_filename[0] = '\0';
  1390.   list_filename[0] = '\0';
  1391.   warnlevel = 0;
  1392.  
  1393.   while(argc > 1 && argv[1][0] == '-') {
  1394.     switch(argv[1][1]) {
  1395.       case 'o': /* output file name */
  1396.         if(argv[1][2] != '\0')
  1397.       strcpy(out_filename, &argv[1][2]);
  1398.     else {
  1399.       if(argc < 3) {
  1400.         fputs("-o option requires a file name\n", stderr);
  1401.         exit(EXIT_FAILURE);
  1402.       }
  1403.       strcpy(out_filename, argv[2]);
  1404.       argc--;
  1405.       argv++;
  1406.     }
  1407.     break;
  1408.  
  1409.       case 'i': case 'I': /* output hex format (ihx8m/ihx16) */
  1410.     if(strcasecmp(&argv[1][1], "ihx8m") == 0)
  1411.       out_format = IHX8M;
  1412.     else if(strcasecmp(&argv[1][1], "ihx16") == 0)
  1413.       out_format = IHX16;
  1414.     else
  1415.       goto usage;
  1416.     break;
  1417.  
  1418.       case 'p': case 'P': /* PIC type */
  1419.     if(!((argv[1][2] == 'i' || argv[1][2] == 'I') &&
  1420.          (argv[1][3] == 'c' || argv[1][3] == 'C')))
  1421.       goto usage;
  1422.  
  1423.     for(pic_type = pic_types; pic_type->name != NULL; pic_type++) {
  1424.       if(strcasecmp(pic_type->name, &argv[1][4]) == 0)
  1425.         break;
  1426.     }
  1427.  
  1428.     if(pic_type->name == NULL) {
  1429.       fprintf(stderr, "Invalid device type '%s'\n", &argv[1][1]);
  1430.       exit(EXIT_FAILURE);
  1431.     }
  1432.  
  1433.     prog_mem_size = pic_type->progmem_size;
  1434.     reg_file_limit = pic_type->regfile_limit;
  1435.     break;
  1436.  
  1437.       case 'l': /* listing/list filename */
  1438.     listing = 1;
  1439.     if(argv[1][2] != '\0')
  1440.       strcpy(list_filename, &argv[1][2]);
  1441.     break;
  1442.  
  1443.       case 's':
  1444.         symdump = 1;
  1445.         break;
  1446.  
  1447.       case 'w': /* warning mode (gives some more warnings) */
  1448.     if(argv[1][2] != '\0') {
  1449.       warnlevel = atoi(&argv[1][2]);
  1450.     } else {
  1451.       warnlevel = 1;
  1452.     }
  1453.     break;
  1454.  
  1455.       case 'v': /* version info */
  1456.     fprintf(stderr,
  1457.         "12/14-bit PIC assembler " VERSION
  1458.         " -- Copyright 1995-1998 by Timo Rossi\n"
  1459.     "AmigaOS version beta2 by RDC <rdc@cch.pmc.ru>\n");
  1460.     break;
  1461.     
  1462.       case '-': /* end of option list */
  1463.       case '\0':
  1464.     argc--;
  1465.     argv++;
  1466.     goto opt_done;
  1467.  
  1468.       default:
  1469.     goto usage;
  1470.     }
  1471.     argc--;
  1472.     argv++;
  1473.   }
  1474.  
  1475. opt_done:
  1476.   if(argc != 2) {
  1477. usage:
  1478.     fputs("Usage: picasm [-o<objname>] [-l<listfile>] [-s] [-ihx8m/ihx16]\n"
  1479.       "              [-pic<device>] [-w[n]] [-version] <filename>\n", stderr);
  1480.     exit(EXIT_FAILURE);
  1481.   }
  1482.  
  1483.   strncpy(in_filename, argv[1], sizeof(in_filename)-1);
  1484.   if(strchr(in_filename, '.') == NULL)
  1485.     strcat(in_filename, ".asm");
  1486.  
  1487.   if(out_filename[0] == '\0') {
  1488.     strcpy(out_filename, in_filename);
  1489.     if((p = strrchr(out_filename, '.')) != NULL)
  1490.       *p = '\0';
  1491.   }
  1492.   if(strchr(out_filename, '.') == NULL)
  1493.     strcat(out_filename, ".hex");
  1494.  
  1495.   init_assembler();
  1496.  
  1497.   list_fp = NULL;
  1498.   if(listing) {
  1499.     if(list_filename[0] == '\0') {
  1500.       strcpy(list_filename, in_filename);
  1501.       if((p = strrchr(list_filename, '.')) != NULL)
  1502.     *p = '\0';
  1503.       strcat(list_filename, ".lst");
  1504.     }
  1505.  
  1506.     if((list_fp = fopen(list_filename, "w")) == NULL)
  1507.       fatal_error("Can't create listing file '%s'", list_filename);
  1508.  
  1509.     ti = time(NULL);
  1510.     tm = localtime(&ti);
  1511.  
  1512.     fprintf(list_fp, "** 12/14-bit PIC assembler " VERSION "\n");
  1513.     fprintf(list_fp, "** %s assembled %s\n",
  1514.         in_filename, asctime(tm));
  1515.   }
  1516.  
  1517.   assembler(in_filename);
  1518.   if(errors == 0) {
  1519.     if(code_generated)
  1520.       write_output(out_filename, out_format);
  1521.     else
  1522.       fputs("No code generated\n", stderr);
  1523.   }
  1524.   else
  1525.     fprintf(stderr, "%d error%s found\n", errors, errors == 1 ? "" : "s");
  1526.  
  1527.   if(warnings != 0)
  1528.     fprintf(stderr, "%d warning%s\n", warnings, warnings == 1 ? "" : "s");
  1529.  
  1530.   if(list_fp)
  1531.     {
  1532.       if(symdump)
  1533.         dump_symtab(list_fp);
  1534.       fclose(list_fp);
  1535.     }
  1536.   return EXIT_SUCCESS;
  1537. }
  1538.